
// #include <vector>
// #include<iostream>
// #include<stdio.h>
// #include <algorithm>
#include<stdio.h>
#include <stdlib.h>

// #define HelperMin(a, b) std::min(a, b)
// #define HelperMax(a, b) std::max(a, b)

__aicore__ float HelperMin(float a, float b)
{
  if (a<b) return a; return b;
}

__aicore__ float HelperMax(float a, float b)
{
  if (a>b) return a; return b;
}

__aicore__ inline void MaxMin(float lhs, float rhs, float& min, float& max) {
  if (lhs >= rhs) {
    min = rhs;
    max = lhs;
  } else {
    min = lhs;
    max = rhs;
  }
}

struct BoxInfoPtr {
    float score_;
    int16_t index_;
};


struct SelectedIndex {
    int64_t batch_index_ = 0;
    int64_t class_index_ = 0;
    int64_t box_index_ = 0;
};



__aicore__ inline bool SuppressByIOU(
  // const float* boxes_data, 
  int32_t box_offset, 
  AscendC::GlobalTensor<float> box_data,
  int64_t box_index1, int64_t box_index2,
                          int64_t center_point_box, float iou_threshold) {
  float x1_min{};
  float y1_min{};
  float x1_max{};
  float y1_max{};
  float x2_min{};
  float y2_min{};
  float x2_max{};
  float y2_max{};
  float intersection_x_min{};
  float intersection_x_max{};
  float intersection_y_min{};
  float intersection_y_max{};

  // const float* box1 = boxes_data + 4 * box_index1;
  // const float* box2 = boxes_data + 4 * box_index2;
  float box1[4] = {box_data.GetValue(box_offset+4 * box_index1), 
                  box_data.GetValue(box_offset+4 * box_index1+1), 
                  box_data.GetValue(box_offset+4 * box_index1+2), 
                  box_data.GetValue(box_offset+4 * box_index1+3)};

  float box2[4] = {box_data.GetValue(box_offset+4 * box_index2), 
                  box_data.GetValue(box_offset+4 * box_index2+1), 
                  box_data.GetValue(box_offset+4 * box_index2+2), 
                  box_data.GetValue(box_offset+4 * box_index2+3)};

  // center_point_box_ only support 0 or 1
  if (0 == center_point_box) {
    // boxes data format [y1, x1, y2, x2],
    MaxMin(box1[1], box1[3], x1_min, x1_max);
    MaxMin(box2[1], box2[3], x2_min, x2_max);

    intersection_x_min = HelperMax(x1_min, x2_min);
    intersection_x_max = HelperMin(x1_max, x2_max);
    if (intersection_x_max <= intersection_x_min)
      return false;

    MaxMin(box1[0], box1[2], y1_min, y1_max);
    MaxMin(box2[0], box2[2], y2_min, y2_max);
    intersection_y_min = HelperMax(y1_min, y2_min);
    intersection_y_max = HelperMin(y1_max, y2_max);
    if (intersection_y_max <= intersection_y_min)
      return false;
  } else {
    // 1 == center_point_box_ => boxes data format [x_center, y_center, width, height]
    float box1_width_half = box1[2] / 2;
    float box1_height_half = box1[3] / 2;
    float box2_width_half = box2[2] / 2;
    float box2_height_half = box2[3] / 2;

    x1_min = box1[0] - box1_width_half;
    x1_max = box1[0] + box1_width_half;
    x2_min = box2[0] - box2_width_half;
    x2_max = box2[0] + box2_width_half;

    intersection_x_min = HelperMax(x1_min, x2_min);
    intersection_x_max = HelperMin(x1_max, x2_max);
    if (intersection_x_max <= intersection_x_min)
      return false;

    y1_min = box1[1] - box1_height_half;
    y1_max = box1[1] + box1_height_half;
    y2_min = box2[1] - box2_height_half;
    y2_max = box2[1] + box2_height_half;

    intersection_y_min = HelperMax(y1_min, y2_min);
    intersection_y_max = HelperMin(y1_max, y2_max);
    if (intersection_y_max <= intersection_y_min)
      return false;
  }

  const float intersection_area = (intersection_x_max - intersection_x_min) *
                                  (intersection_y_max - intersection_y_min);

  if (intersection_area <= .0f) {
    return false;
  }

  const float area1 = (x1_max - x1_min) * (y1_max - y1_min);
  const float area2 = (x2_max - x2_min) * (y2_max - y2_min);
  const float union_area = area1 + area2 - intersection_area;

  if (area1 <= .0f || area2 <= .0f || union_area <= .0f) {
    return false;
  }

  const float intersection_over_union = intersection_area / union_area;

  return intersection_over_union > iou_threshold;
}

